home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games: 500 MB Amiga Software / 500 MB Amiga Software - Euber 130 - Amiga Games Disc & Mag.iso / spiele / publicdomain / uchess / uchesssrc.lha / book.c < prev    next >
C/C++ Source or Header  |  1992-12-17  |  10KB  |  397 lines

  1. /*
  2.  * book.c - C source for GNU CHESS
  3.  *
  4.  * Copyright (c) 1988,1989,1990 John Stanback
  5.  * Copyright (c) 1992 Free Software Foundation
  6.  *
  7.  * This file is part of GNU CHESS.
  8.  *
  9.  * GNU Chess is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2, or (at your option)
  12.  * any later version.
  13.  *
  14.  * GNU Chess is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with GNU Chess; see the file COPYING.  If not, write to
  21.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include "gnuchess.h"
  25.  
  26. unsigned int urand (void);
  27.  
  28. extern char mvstr[4][6];
  29. int bookcount = 0;
  30. static struct bookentry
  31. {
  32.   unsigned long bookkey;
  33.   unsigned long bookbd;
  34.   unsigned INTSIZE2 bmove;
  35.   unsigned INTSIZE2 hint;
  36.   unsigned char count;
  37.   unsigned char flags;
  38. } *OpenBook;
  39. static struct bookentry *BookTable[BKTBLSIZE];
  40. void
  41. GetOpenings (void)
  42.  
  43. /*
  44.  * Read in the Opening Book file and parse the algebraic notation for a move
  45.  * into an unsigned integer format indicating the from and to square. Create
  46.  * a linked list of opening lines of play, with entry->next pointing to the
  47.  * next line and entry->move pointing to a chunk of memory containing the
  48.  * moves. More Opening lines of up to 100 half moves may be added to
  49.  * gnuchess.book.
  50.  * But now its a hashed table by position which yields a move or moves for 
  51.  * each position. It no longer knows about openings per say only positions
  52.  * and recommended moves in those positions.
  53.  */
  54. #ifndef BOOK
  55. #define BOOK "/usr/games/lib/gnuchess.book"
  56. #endif /* BOOK */
  57. {
  58.   FILE *fd;
  59.   REG struct bookentry *OB, *OC;
  60.   REG INTSIZE int i, f, t;
  61.   char opening[80];
  62.   char msg[80];
  63.   INTSIZE int xside, doit, c, side;
  64.   INTSIZE int rf, rt;
  65.   unsigned INTSIZE mv;
  66. #ifndef AMIGA
  67.   int bs;
  68.   unsigned long ltmp;
  69. #endif
  70.  
  71.   /* allocate space for the book */
  72.   OpenBook = (struct bookentry *) malloc(BOOKSIZE*sizeof(struct bookentry));
  73.  
  74.   for (i = 0; i < BKTBLSIZE; i++)
  75.     {
  76.       BookTable[i] = &OpenBook[BOOKSIZE / BKTBLSIZE * i];
  77.     }
  78. #ifdef BINBOOK
  79.   fd = fopen (BINBOOK, "r");
  80.   if (fd != NULL)
  81.     {
  82.       fscanf(fd, "%d\n", &bs);
  83.       fscanf(fd, "%d\n", &bookcount);
  84.       if (bs == BOOKSIZE)
  85.     {
  86.       if(0>fread(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  87.         perror("fread");
  88.       /* set every thing back to start game */
  89.       Book = BOOKFAIL;
  90.       for (i = 0; i < 64; i++)
  91.         {
  92.           board[i] = Stboard[i];
  93.           color[i] = Stcolor[i];
  94.         }
  95.       fclose(fd);
  96.       return;
  97.       
  98.     }
  99.       fclose(fd);
  100.     }
  101. #endif
  102.  
  103.   for (OB = OpenBook; OB < &OpenBook[BOOKSIZE]; OB++)
  104.     OB->count = 0;
  105.   if ((fd = fopen (BOOK, "r")) == NULL)
  106.     fd = fopen ("gnuchess.book", "r");
  107.   if (fd != NULL)
  108.     {
  109.       ShowMessage("Loading Book..");
  110.       ShowMessage("Please Wait...");
  111.       OC = NULL;
  112.       /* setvbuf(fd,buffr,_IOFBF,2048); */
  113.       side = white;
  114.       xside = black;
  115.       hashbd = hashkey = 0;
  116.       for (i = 0; i < 64; i++)
  117.     {
  118.       board[i] = Stboard[i];
  119.       color[i] = Stcolor[i];
  120.     }
  121.       i = 0;
  122.  
  123.       while ((c = parse (fd, &mv, side, opening)) >= 0)
  124.     if (c == 1)
  125.       {
  126.  
  127.         /*
  128.          * if not first move of an opening and first time we have
  129.          * seen it save next move as hint
  130.          */
  131.         if (i && OB->count == 1)
  132.           OB->hint = mv & 0x3f3f;
  133.         OC = OB;        /* save for end marking */
  134.         doit = true;
  135.  
  136.         /*
  137.          * see if this position and move already exist from some
  138.          * other opening
  139.          */
  140.         /* is this ethical, to offer the bad move as a hint????? */
  141.         for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  142.           {
  143.         if (OB->bookkey == hashkey
  144.             && OB->bookbd == hashbd
  145.             && (OB->flags & SIDEMASK) == side
  146.             && OB->bmove == mv)
  147.           {
  148.             
  149.             /*
  150.              * yes so just bump count - count is used to choose
  151.              * opening move in proportion to its presence in the
  152.              * book
  153.              */
  154.             doit = false;
  155.             OB->count++;
  156.             if (OB->count < 1)
  157.               OB->count--;
  158.             break;
  159.           }
  160.         /* Book is hashed into BKTBLSIZE chunks based on hashkey */
  161.         if (OB == &OpenBook[BOOKSIZE - 1])
  162.           OB = OpenBook;
  163.           }
  164.         /* doesn`t exist so add it to the book */
  165.         if (doit)
  166.           {
  167.         bookcount++;
  168.         OB->bookkey = hashkey;
  169.         OB->bookbd = hashbd;
  170.         OB->bmove = mv;
  171.         OB->hint = 0;
  172.         OB->count = 1;
  173.         OB->flags = side;
  174.           }
  175.         /* now update the board and hash values */
  176.         /* should really check the moves as we do this, but??? */
  177.         f = mv >> 8 & 0x3F;
  178.         t = mv & 0x3F;
  179.         if (board[t] != no_piece)
  180.           {
  181.         if (color[t] != xside)
  182.           {
  183.             algbr (f, t, false);
  184.             sprintf (msg, CP[211], i + 1, mvstr, opening);
  185.             ShowMessage (msg);
  186.           }
  187.         UpdateHashbd (xside, board[t], -1, t);
  188.           }
  189.         if (board[f] == no_piece || color[f] != side)
  190.           {
  191.         algbr (f, t, false);
  192.         sprintf (msg, CP[211], i + 1, mvstr, opening);
  193.         ShowMessage (msg);
  194.           }
  195.         UpdateHashbd (side, board[f], f, t);
  196.         board[t] = board[f];
  197.         color[t] = color[f];
  198.         color[f] = neutral;
  199.         board[f] = no_piece;
  200.         if ((board[t] == king) && ((mv == BLACKCASTLE) || (mv == WHITECASTLE) || (mv == LONGBLACKCASTLE) || (mv == LONGWHITECASTLE)))
  201.           {
  202.  
  203.         if (t > f)
  204.           {
  205.             rf = f + 3;
  206.             rt = t - 1;
  207.           }
  208.         else
  209.           {
  210.             rf = f - 4;
  211.             rt = t + 1;
  212.           }
  213.         board[rt] = rook;
  214.         color[rt] = side;
  215.         board[rf] = no_piece;
  216.         color[rf] = neutral;
  217.         UpdateHashbd (side, rook, rf, rt);
  218.           }
  219.         i++;
  220.         xside = side;
  221.         side = side ^ 1;
  222.       }
  223.     else if (c == 0 && i > 0)
  224.       {
  225.         /* Mark last move as end of an opening */
  226.         /* might want to terminate? */
  227.         OB->flags |= BOOKEND;
  228.         if (i > 1)
  229.           OC->flags |= BOOKEND;
  230.         /* reset for next opening */
  231.         side = white;
  232.         hashbd = hashkey = 0;
  233.         for (i = 0; i < 64; i++)
  234.           {
  235.         board[i] = Stboard[i];
  236.         color[i] = Stcolor[i];
  237.           }
  238.         i = 0;
  239.  
  240.       }
  241.       fclose (fd);
  242. #ifdef BINBOOK
  243.       fd = fopen (BINBOOK, "w");
  244.       fprintf(fd, "%d\n%d\n", BOOKSIZE, bookcount);
  245.       if(0>fwrite(OpenBook, sizeof(struct bookentry), BOOKSIZE, fd))
  246.     perror("fwrite");
  247.       fclose (fd);
  248. #endif
  249. #if !defined CHESSTOOL && !defined XBOARD
  250.       ShowMessage("  ");
  251.       ShowMessage("  ");
  252.       ShowMessage("  ");
  253.       ShowMessage("  ");
  254.       ShowMessage("  ");
  255.       ShowMessage("  ");
  256.       sprintf (msg, CP[213], bookcount, BOOKSIZE);
  257.       ShowMessage (msg);
  258. #endif
  259.       /* set every thing back to start game */
  260.       Book = BOOKFAIL;
  261.       for (i = 0; i < 64; i++)
  262.     {
  263.       board[i] = Stboard[i];
  264.       color[i] = Stcolor[i];
  265.     }
  266.     }
  267.   else
  268.     {
  269. #if !defined CHESSTOOL && !defined XBOARD
  270.       ShowMessage (CP[212]);
  271. #endif
  272.       Book = 0;
  273.     }
  274. }
  275.  
  276.  
  277. int
  278. OpeningBook (unsigned INTSIZE *hint, INTSIZE int side)
  279.      
  280. /*
  281.  * Go thru each of the opening lines of play and check for a match with the
  282.  * current game listing. If a match occurs, generate a random number. If this
  283.  * number is the largest generated so far then the next move in this line
  284.  * becomes the current "candidate". After all lines are checked, the
  285.  * candidate move is put at the top of the Tree[] array and will be played by
  286.  * the program. Note that the program does not handle book transpositions.
  287.  */
  288.  
  289. {
  290.   INTSIZE pnt;
  291.   unsigned INTSIZE m;
  292.   unsigned r, cnt, tcnt, ccnt;
  293.   REG struct bookentry *OB, *OC;
  294.   int possibles = TrPnt[2] - TrPnt[1];
  295.  
  296.   srand ((unsigned int) time ((long *) 0));
  297.   m = 0;
  298.   cnt = 0;
  299.   tcnt = 0;
  300.   ccnt = 0;
  301.   OC = NULL;
  302.   
  303.  
  304.   /*
  305.    * find all the moves for this position  - count them and get their total
  306.    * count
  307.    */
  308.   for (OB = BookTable[hashkey & BOOKMASK]; OB->count; OB++)
  309.     {
  310.       if (OB->bookkey == hashkey
  311.       && OB->bookbd == hashbd
  312.       && ((OB->flags) & SIDEMASK) == side)
  313.     {
  314.       if (OB->bmove & BADMOVE)
  315.         {
  316.           m = OB->bmove ^ BADMOVE;
  317.           /* is the move is in the MoveList */
  318.           for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  319.         {
  320.           if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  321.             {
  322.               if (--possibles)
  323.             {
  324.               Tree[pnt].score = DONTUSE;
  325.               break;
  326.             }
  327.             }
  328.         }
  329.  
  330.         }
  331.       else
  332.         {
  333.           OC = OB;
  334.           cnt++;
  335.           tcnt += OB->count;
  336.         }
  337.     }
  338.     }
  339.   /* if only one just do it */
  340.   if (cnt == 1)
  341.     {
  342.       m = OC->bmove;
  343.     }
  344.   else
  345.     /* more than one must choose one at random */
  346.   if (cnt > 1)
  347.     {
  348.       /* pick a number */
  349.       r = urand () % 1000;
  350.  
  351.       for (OC = BookTable[hashkey & BOOKMASK]; OC->count; OC++)
  352.     {
  353.       if (OC->bookkey == hashkey
  354.           && OC->bookbd == hashbd
  355.           && ((OC->flags) & SIDEMASK) == side
  356.           && !(OC->bmove & BADMOVE))
  357.         {
  358.           ccnt += OC->count;
  359.           if (((ccnt * BOOKRAND) / tcnt) >= r)
  360.         {
  361.           m = OC->bmove;
  362.           break;
  363.         }
  364.         }
  365.     }
  366.     }
  367.   else
  368.     {
  369.       /* none decrement count of no finds */
  370.       Book--;
  371.       return false;
  372.     }
  373.   /* make sure the move is in the MoveList */
  374.   for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  375.     {
  376.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  377.     {
  378.           Tree[pnt].flags |= book;
  379.       Tree[pnt].score = 0;
  380.       break;
  381.     }
  382.     }
  383.   /* Make sure its the best */
  384.  
  385.   pick (TrPnt[1], TrPnt[2] - 1);
  386.   if (Tree[TrPnt[1]].score)
  387.     {
  388.       /* no! */
  389.       Book--;
  390.       return false;
  391.     }
  392.   /* ok pick up the hint and go */
  393.   *hint = OC->hint;
  394.   Book = ((OC->flags & BOOKEND) && ((urand () % 1000) > BOOKENDPCT)) ? 0 : BOOKFAIL;
  395.   return true;
  396. }
  397.